#pragma once

template<typename T>
class VScrollbar : public UIElement
{
	Texture* m_backGTex;
	Texture* m_knobTex;
	Texture* m_leftDown;
	Texture* m_leftUp;
	Texture* m_rightDown;
	Texture* m_rightUp;

	Vertex3FRHWT m_backGV[4];
	Vertex3FRHWT m_knobV[4];
	Vertex3FRHWT m_rightV[4];
	Vertex3FRHWT m_leftV[4];

	bool m_knobPressed;
	ui32 m_stateLeft, m_stateRight;
	ui32 m_leftClick, m_rightClick;
	ui32 m_pct;
	ui32 m_lastCheck;
	ui32 m_rangeMin;
	ui32 m_rangeMax;

	typedef void (T::*ScrollCallback)(VScrollbar* pBar, ui32 m_value);
	ScrollCallback m_onScroll;

	T* m_instance;

public:
	VScrollbar(ui32 x, ui32 y, ui32 sizeY, T* instance)
	{
		ui32 sizeX = sizeY;
		m_instance = instance;
		m_position.x = (float)x;
		m_position.y = (float)y;

		m_size.x = 18;
		m_size.y = (float)sizeX;

		m_backGTex = CTextureHandler::GetInstance()->GetTexture("Interface\\Tooltips\\ChatBubble-Background.blp");
		m_leftUp = CTextureHandler::GetInstance()->GetTexture("Interface\\BUTTONS\\UI-ScrollBar-ScrollDownButton-Up.blp");
		m_leftDown = CTextureHandler::GetInstance()->GetTexture("Interface\\BUTTONS\\UI-ScrollBar-ScrollDownButton-Down.blp");
		m_rightUp = CTextureHandler::GetInstance()->GetTexture("Interface\\BUTTONS\\UI-ScrollBar-ScrollUpButton-Up.blp");
		m_rightDown = CTextureHandler::GetInstance()->GetTexture("Interface\\BUTTONS\\UI-ScrollBar-ScrollUpButton-Down.blp");
		m_knobTex = CTextureHandler::GetInstance()->GetTexture("Interface\\BUTTONS\\UI-ScrollBar-Knob.blp");

		m_backGV[0].x = x;
		m_backGV[0].y = (float)y + 10.0f;
		m_backGV[0].u = 0.0f;
		m_backGV[0].v = 0.0f;

		m_backGV[1].x = x + 18;
		m_backGV[1].y = (float)y + 10.0f;
		m_backGV[1].u = 1.0f;
		m_backGV[1].v = 0.0f;

		m_backGV[2].x = x + 18;
		m_backGV[2].y = y + sizeX;
		m_backGV[2].u = 1.0f;
		m_backGV[2].v = 1.0f;

		m_backGV[3].x = x;
		m_backGV[3].y = y + sizeX;
		m_backGV[3].u = 0.0f;
		m_backGV[3].v = 1.0f;

		m_leftV[0].x = (float)x;
		m_leftV[0].y = (float)y;
		m_leftV[0].u = 24 / 32.0f;
		m_leftV[0].v = 24 / 32.0f;//24 / 32.0f;

		m_leftV[1].x = (float)x + 18;
		m_leftV[1].y = (float)y;
		m_leftV[1].u = 6 / 32.0f;
		m_leftV[1].v = 24 / 32.0f;

		m_leftV[2].x = (float)x + 18;
		m_leftV[2].y = (float)y + 18;
		m_leftV[2].u = 6 / 32.0f;
		m_leftV[2].v = 6 / 32.0f;

		m_leftV[3].x = (float)x;
		m_leftV[3].y = (float)y + 18;
		m_leftV[3].u = 24 / 32.0f;
		m_leftV[3].v = 6 / 32.0f;

		m_rightV[0].x = x;
		m_rightV[0].y = (float)y + sizeX - 18;
		m_rightV[0].u = 24 / 32.0f;
		m_rightV[0].v = 24 / 32.0f;

		m_rightV[1].x = (float)x + 18;
		m_rightV[1].y = (float)y + sizeX - 18;
		m_rightV[1].u = 6 / 32.0f;
		m_rightV[1].v = 24 / 32.0f;

		m_rightV[2].x = (float)x + 18;
		m_rightV[2].y = y + sizeX;
		m_rightV[2].u = 6 / 32.0f;
		m_rightV[2].v = 6 / 32.0f;

		m_rightV[3].x = x;
		m_rightV[3].y = y + sizeX;
		m_rightV[3].u = 24 / 32.0f;//24 / 32.0f;
		m_rightV[3].v = 6 / 32.0f;//24 / 32.0f;

		m_knobV[0].x = (float)x;
		m_knobV[0].y = (float)y + 18.0f;
		m_knobV[0].u = 6 / 32.0f;
		m_knobV[0].v = 6 / 32.0f;

		m_knobV[1].x = (float)x + 18.0f;
		m_knobV[1].y = (float)y + 18.0f;
		m_knobV[1].u = 24 / 32.0f;
		m_knobV[1].v = 6 / 32.0f;

		m_knobV[2].x = (float)x + 18.0f;
		m_knobV[2].y = (float)y + 36.0f;
		m_knobV[2].u = 24 / 32.0f;
		m_knobV[2].v = 24 / 32.0f;

		m_knobV[3].x = (float)x;
		m_knobV[3].y = (float)y + 36.0f;
		m_knobV[3].u = 6 / 32.0f;
		m_knobV[3].v = 24 / 32.0f;

		m_knobPressed = false;
		m_stateLeft = m_stateRight = 0;
		m_leftClick = m_rightClick = 0;
		m_pct = 0;
		m_lastCheck = 0;
		m_pUserData = 0;
		m_onScroll = 0;
	}

	void Draw()
	{
		if(!m_visible)
			return;

		if(!sMouse.LeftDown())
			m_knobPressed = false;
		ui32 now = GetTickCount();
		if(now - m_lastCheck > 25)
		{
			if(m_stateLeft && m_pct > 0 && now - m_leftClick > 300)
			{
				m_pct -= 1;
				m_knobV[0].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f);
				m_knobV[1].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f);
				m_knobV[2].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f) + 18;
				m_knobV[3].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f) + 18;
				m_lastCheck = now;
				if(m_onScroll)
					(m_instance->*m_onScroll)(this, (ui32)floor((m_pct / 100.0f) * (m_rangeMax - m_rangeMin) + m_rangeMin));
			}
			else if(m_stateRight && m_pct < 100 && now - m_rightClick > 300)
			{
				m_pct += 1;
				m_knobV[0].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f);
				m_knobV[1].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f);
				m_knobV[2].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f) + 18;
				m_knobV[3].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f) + 18;
				m_lastCheck = now;
				if(m_onScroll)
					(m_instance->*m_onScroll)(this, (ui32)floor((m_pct / 100.0f) * (m_rangeMax - m_rangeMin) + m_rangeMin));
			}
		}

		sD3D->SetFVF(VERTEX3FRHWT);
		sD3D->SetTexture(0, *m_backGTex);
		sD3D->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, m_backGV, sizeof(Vertex3FRHWT));

		if(!m_stateLeft)
			sD3D->SetTexture(0, *m_leftUp);
		else
			sD3D->SetTexture(0, *m_leftDown);
		sD3D->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, m_leftV, sizeof(Vertex3FRHWT));

		if(!m_stateRight)
			sD3D->SetTexture(0, *m_rightUp);
		else
			sD3D->SetTexture(0, *m_rightDown);
		sD3D->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, m_rightV, sizeof(Vertex3FRHWT));

		sD3D->SetTexture(0, *m_knobTex);
		sD3D->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, m_knobV, sizeof(Vertex3FRHWT));
	}

	void MouseActivity(bool left, Vertex2F pos, bool up)
	{
		if(up)
		{
			m_knobPressed = false;
			m_stateRight = 0;
			m_stateLeft = 0;
		}

		if(pos.x >= m_knobV[0].x && pos.x <= m_knobV[0].x + 18.0f &&
			pos.y >= m_knobV[0].y && pos.y <= m_knobV[0].y + 18.0f)
		{
			m_knobPressed = !up;
		}
		
		if(pos.x >= m_position.x && pos.x <= m_position.x + m_size.x &&
				pos.y >= m_position.y + 18 && pos.y <= m_position.y + m_size.y - 18 && up)
		{
			if(pos.y - m_position.y - 18 < 9.0f)
			{
				m_knobV[0].y = (float)m_position.y + 18.0f;
				m_knobV[1].y = (float)m_position.y + 18.0f;
				m_knobV[2].y = (float)m_position.y + 36.0f;
				m_knobV[3].y = (float)m_position.y + 36.0f;
				m_pct = 0;
				if(m_onScroll)
					(m_instance->*m_onScroll)(this, (ui32)floor((m_pct / 100.0f) * (m_rangeMax - m_rangeMin) + m_rangeMin));
			}
			else if(m_position.y + m_size.y - 18 - pos.y < 9.0f)
			{
				m_knobV[0].y = (float)m_position.y + m_size.y - 36.0f;
				m_knobV[1].y = (float)m_position.y + m_size.y - 36.0f;
				m_knobV[2].y = (float)m_position.y + m_size.y - 18.0f;
				m_knobV[3].y = (float)m_position.y + m_size.y - 18.0f;
				m_pct = 100;
				if(m_onScroll)
					(m_instance->*m_onScroll)(this, (ui32)floor((m_pct / 100.0f) * (m_rangeMax - m_rangeMin) + m_rangeMin));
			}
			else
			{
				m_knobV[0].y = pos.y - 9.0f;
				m_knobV[1].y = pos.y - 9.0f;
				m_knobV[2].y = pos.y + 9.0f;
				m_knobV[3].y = pos.y + 9.0f;
				m_pct = (ui32)(floor((pos.y - m_position.y - 27.0f) / (m_size.y - 54.0f) * 100));
				if(m_onScroll)
					(m_instance->*m_onScroll)(this, (ui32)floor((m_pct / 100.0f) * (m_rangeMax - m_rangeMin) + m_rangeMin));
			}
		}
		else if(pos.x >= m_position.x && pos.x < m_position.x + 18.0f && 
			pos.y >= m_position.y && pos.y <= m_position.y + 18.0f)
		{
			m_stateLeft = up ? 0 : 1;
			m_leftClick = GetTickCount();
			if(up)
			{
				if(m_pct > 0)
					m_pct -= 1;
				m_knobV[0].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f);
				m_knobV[1].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f);
				m_knobV[2].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f) + 18;
				m_knobV[3].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f) + 18;
				if(m_onScroll)
					(m_instance->*m_onScroll)(this, (ui32)floor((m_pct / 100.0f) * (m_rangeMax - m_rangeMin) + m_rangeMin));
			}

		}
		else if(pos.x > m_position.x && pos.x <= m_position.x + 18 &&
			pos.y >= m_position.y + m_size.y - 18 && pos.y <= m_position.y + m_size.y)
		{
			m_stateRight = up ? 0 : 1;
			m_rightClick = GetTickCount();
			if(up)
			{
				if(m_pct < 100)
					m_pct += 1;
				m_knobV[0].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f);
				m_knobV[1].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f);
				m_knobV[2].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f) + 18;
				m_knobV[3].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f) + 18;
				if(m_onScroll)
					(m_instance->*m_onScroll)(this, (ui32)floor((m_pct / 100.0f) * (m_rangeMax - m_rangeMin) + m_rangeMin));
			}
		}
	}

	void OnMouseMove(ui32 x, ui32 y, bool leftDown, bool rightDown)
	{
		if(!m_knobPressed)
			return;
		Vertex2F pos((float)x, (float)y);
		if(pos.x >= m_position.x && pos.x <= m_position.x + m_size.x &&
				pos.y >= m_position.y + 18 && pos.y <= m_position.y + m_size.y - 18)
		{
			if(pos.y - m_position.y - 18 < 9.0f)
			{
				m_knobV[0].y = (float)m_position.y + 18.0f;
				m_knobV[1].y = (float)m_position.y + 18.0f;
				m_knobV[2].y = (float)m_position.y + 36.0f;
				m_knobV[3].y = (float)m_position.y + 36.0f;
				m_pct = 0;
				if(m_onScroll)
					(m_instance->*m_onScroll)(this, (ui32)floor((m_pct / 100.0f) * (m_rangeMax - m_rangeMin) + m_rangeMin));
			}
			else if(m_position.y + m_size.y - 18 - pos.y < 9.0f)
			{
				m_knobV[0].y = (float)m_position.y + m_size.y - 36.0f;
				m_knobV[1].y = (float)m_position.y + m_size.y - 36.0f;
				m_knobV[2].y = (float)m_position.y + m_size.y - 18.0f;
				m_knobV[3].y = (float)m_position.y + m_size.y - 18.0f;
				m_pct = 100;
				if(m_onScroll)
					(m_instance->*m_onScroll)(this, (ui32)floor((m_pct / 100.0f) * (m_rangeMax - m_rangeMin) + m_rangeMin));
			}
			else
			{
				m_knobV[0].y = pos.y - 9.0f;
				m_knobV[1].y = pos.y - 9.0f;
				m_knobV[2].y = pos.y + 9.0f;
				m_knobV[3].y = pos.y + 9.0f;
				m_pct = (ui32)(floor((pos.y - m_position.y - 27.0f) / (m_size.y - 54.0f) * 100));
				if(m_onScroll)
					(m_instance->*m_onScroll)(this, (ui32)floor((m_pct / 100.0f) * (m_rangeMax - m_rangeMin) + m_rangeMin));
			}
		}
	}

	void SetCallback(ScrollCallback pFunc) { m_onScroll = pFunc; }
	void* m_pUserData;
	void SetRange(ui32 min, ui32 max) { m_rangeMin = min; m_rangeMax = max; }
	void SetValue(ui32 value)
	{
		m_pct = (ui32)floor(((float)value - m_rangeMin) / (m_rangeMax - m_rangeMin) * 100);
		m_knobV[0].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f);
		m_knobV[1].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f);
		m_knobV[2].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f) + 18;
		m_knobV[3].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f) + 18;
	}

	ui32 GetValue()
	{
		ui32 diff = m_rangeMax - m_rangeMin;
		return ui32(m_rangeMin + (m_pct / 100.0f) * diff);
	}

	void setPosition(i32 x, i32 y) {
		i32 diffX = x - m_position.x;
		i32 diffY = y - m_position.y;
		ModPosition(diffX, diffY);
	}

	ui32 getMaximum() { return m_rangeMax; }
	ui32 getMinimum() { return m_rangeMin; }

	void increment() {
		m_pct += 1;
		if(m_pct > 100)
			m_pct = 100;
		m_knobV[0].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f);
		m_knobV[1].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f);
		m_knobV[2].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f) + 18;
		m_knobV[3].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f) + 18;
	}

	void decrement() {
		if(m_pct > 0)
			m_pct -= 1;
		m_knobV[0].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f);
		m_knobV[1].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f);
		m_knobV[2].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f) + 18;
		m_knobV[3].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f) + 18;
	}

	void setHeight(ui32 height) {
		i32 diffy = height - m_size.y;
		m_size.y = height;

		m_backGV[2].y += diffy;
		m_backGV[3].y += diffy;

		for(ui32 i = 0; i < 4; ++i)
		{
			//m_knobV[i].y += diffy;
			//m_backGV[i].y += diffy;
			//m_leftV[i].y += diffy;
			m_rightV[i].y += diffy;
		}

		m_knobV[0].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f);
		m_knobV[1].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f);
		m_knobV[2].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f) + 18;
		m_knobV[3].y = (float)m_position.y + 18.0f + (m_size.y - 54.0f) * (m_pct / 100.0f) + 18;
	}

	void ModPosition(i32 x, i32 y)
	{
		m_position.x += x;
		m_position.y += y;
		for(ui32 i = 0; i < 4; ++i)
		{
			m_knobV[i].x += x;
			m_knobV[i].y += y;
			m_backGV[i].x += x;
			m_backGV[i].y += y;
			m_leftV[i].x += x;
			m_leftV[i].y += y;
			m_rightV[i].x += x;
			m_rightV[i].y += y;
		}
	}
};